home *** CD-ROM | disk | FTP | other *** search
- .!****************************************************************************
- .!
- .! ANTIC PUBLISHING INC., COPYRIGHT 1985. REPRINTED BY PERMISSION.
- .!
- .! ** Professional GEM ** by Tim Oren
- .!
- .! Proff File by ST enthusiasts at
- .! Case Western Reserve University
- .! Cleveland, Ohio
- .! uucp : decvax!cwruecmp!bammi
- .! csnet: bammi@case
- .! arpa : bammi%case@csnet-relay
- .! compuserve: 71515,155
- .!
- .!****************************************************************************
- .!
- .!
- .!****************************************************************************
- .!
- .! Begin Part 16
- .!
- .!****************************************************************************
- .!
- .PART XVI Interface Potpourri #1
- .PP
- This issue of ST PRO GEM, number 16 in the series, presents
- code implementing several user interface techniques: progress
- indicators, rubber boxes, and draggable boxes with mouse sensitive
- targets. The code also includes some utility routines for
- handling resources, event calls, and VDI line drawing.
- .PP
- The downloads for this column are available on DL3 of the
- ATARI16 SIG: PCS-58. Note the plural - in addition to the usual C
- sources stored in GMCL16.C, the files GMCL16.RSC, GMCL16.DFN,
- GMCL16.H, and GMCL16.RSH are a template resource for building
- progress boxes. GMCL16.RSC is the resource binary, and GMCL16.H
- is its symbol binding file, to be used with GMCL16.C. The RSH
- file is a C image of the resource - you would need STCREATE to
- regenerate it.
- .PP
- GMCL16.DFN is the binary symbol file for the resource. It is
- in the format used by the NEW ST Resource Construction Set. If
- you are a developer, you should download this new version from DL7
- of PCS-57. It fixes a number of bugs, and has a much faster user
- interface.
- .SH MAKING PROGRESS.
- The need for feedback in interface designs
- has been discussed in previous columns. One instance which is
- often necessary is the so-called progress indicator. A progress
- indicator is used when your application is doing a long operation.
- It shows that the function is continuing satisfactorily, and is
- not hung in a loop. When possible, it also gives an indication of
- the fraction of the operation which has been completed. The
- thermometer bars on the Desktop format and copy operations are
- examples.
- .PP
- The sample code shows two types of progress indicator. Both
- are built within the structure of a dialog resource. The first
- type uses a variable line of text to describe each phase of an
- operation as it occurs. The rewriting of the text provides action
- on the screen; the fact that it is different each time gives
- reassurance that the program is not hung. The second type of
- indicator is the thermometer bar. This is more useful when the
- operation is uniform, allowing you to estimate the fraction
- completed. Let's look at the code.
- .PP
- The routines beg_prog() and end_prog() are common to the two
- types. The code is very similar to the standard dialog handling
- procedure, but is broken into two parts. Beg_prog() assumes that
- the progress indicator box is defined by a dialog tree named
- PROGRESS. Such a tree is provided in GMCL16.RSC. Beg_prog()
- makes the usual calls to center and draw the box. The rectangle
- computed in the centering operation is stored via a GRECT pointer
- passed in the parameter. This rectangle compensates for the
- outline around the box, and must be supplied to end_prog() when
- the operation is complete.
- .PP
- The first version of set_prog() in the download implements
- the changing text progress indicator. It looks in a tree labelled
- STRINGS for the object number which is passed as a parameter. It
- is assumed that this object is a G_STRING. The address of the new
- text is loaded from the object's ob_spec field. (For those with
- the new RCS, it would be easy to alter this routine to use free
- strings. Simply replace the first two lines with:
- .sp
- .ce
- rsrc_gaddr(R_STRING, strno, &saddr);
- .sp
- and supply parameters which are the names of strings in a FRSTR
- box.)
- .PP
- Once the new text is found, the set_text() utility is called
- to update the TEDINFO attached to object PLINE in the PROGRESS
- tree. Set_text() will insert the new text address in te_ptext,
- and the new text length in te_txtlen. Disp_obj() is then used to
- redraw only the rectangle belonging to PLINE.
- .PP
- PLINE must be defined as a G_BOXTEXT object with a solid
- white background, and with the CENTERED attribute set. It must
- extend entirely across the progress box. This guarantees that the
- previous text will be covered over, and the new text will be
- centered in the box.
- .PP
- The second version of set_prog() implements the thermometer
- bar progress indicator. The PROGRESS tree also includes an object
- PROBOX which defines the outline of the thermometer. It is a
- G_BOX object with a solid white background, and a one-outside
- border. The object PROBAR is nested inside it, with the left
- edges matching. PROBAR is also a G_BOX, with a solid red
- background and a one-outside border as well. Set_prog() creates
- the thermometer effect by growing and redrawing PROBAR.
- .PP
- Set_prog() requires two parameters. Maxc is an estimate of
- the total duration of the operation, in arbitrary units. Value is
- the (new) amount completed, in the same units. Set_prog performs
- two operations. First, it computes the fraction value/maxc, and
- sets PROBAR to that fraction of the width of PROBOX. Second, it
- computes the rectangle which is the difference between the old and
- new widths of PROBAR, and redraws only that part of the progress
- box. This prevents an annoying flash on the screen when the
- indicator is updated.
- .PP
- These two types of progress indicators have been presented in
- separate routines for convenience in explanation. You can easily
- combine them in a single procedure to create an indicator with
- both effects.
- .PP
- The final progress indicator routine is called esc_prog().
- During many lengthy operations is desirable to provide an abort
- option to the user. Esc_prog() lets you do this by polling the
- keyboard for an escape (ESC) character. A zero timer value is
- used to guarantee an immediate return if no character is found.
- Characters other than escape are ignored.
- .PP
- Esc_prog() returns TRUE if an abort is requested, and FALSE
- if the operation is to continue. In your application, you can
- either pair calls to set_prog() and esc_prog(), or recode
- set_prog() to automatically make the abort check. In any case,
- you should add an information line to the progress box, telling
- the user how the operation may be halted.
- .PP
- Of course, this type of progress indicator is not the only
- option available on the ST. Other ideas such as changing window
- titles, or displaying a succession of differing icons are equally
- valid. Sometimes the nature of your application may suggest an
- alternate metaphor. For instance, the progress of recalculating a
- spreadsheet might be indicated by darkening successive columns in
- a miniature image of the sheet. Occasionally, the computing
- operation is visual itself, and will not require an explicit
- indicator. An example is redisplaying objects in a 2D or
- 3D drawing program.
- .SH BOXED IN.
- The second part of the download implements two
- types of user interaction using the mouse. The first creates a
- "rubber box" on the screen, that is, a box whose size is
- controlled by moving the mouse. This is similar to the AES
- graf_rubberbox call, but allows the box to move in any direction
- from its origin, while the GEM function only allows movement to
- the lower right.
- .PP
- The second technique allows the user to drag the outline of a
- box around the screen using the mouse. Again, this is similar to
- the AES graf_dragbox call, but this version is augmented with code
- which "hotspots" selectable objects when the mouse and object pass
- over them. These routines are another illustration of the usage
- of the evnt_multi function, and its combination with VDI drawing
- to create new interaction techniques.
- .PP
- The "rubber box" subroutine is called fourway_box(). Its
- parameters are the current VDI handle (NOT a window handle!), and
- two GRECT pointers. The first GRECT must have its g_x and g_y
- initialized with the fixed point of the rubber box. The second
- GRECT contains an outer bound box for the stretching action.
- .PP
- Fourway_box() begins by setting the VDI drawing mode and
- color. The exclusive or, black combination guarantees that
- redrawing a figure twice in the same location will exactly erase
- it. Next, the routine asserts the mouse control flag. This stops
- the window manager from tracking the mouse, with the effect that
- menus will not drop down during the operation.
- .PP
- The fixed coordinates are saved in the variables ox and oy,
- and an initial mouse reading is obtained with graf_mkstate. At
- this point, the event loop is entered.
- .PP
- At each iteration, the loop finds the upper left most of the
- fixed vertex and the current mouse position, and updates the
- tracking GRECT accordingly. A call to the utility rc_intersect()
- is used to restrict the size of the rubber box to the given
- limiting rectangle. Note that if you need a lower limit to the
- size of the rubber box, it can be achieved by adding another GRECT
- pointer "lower" to the parameter list, and using the call
- .sp
- .ce
- rc_union(lower, rubber);
- .sp
- This works because the union operation selects the larger of two
- rectangles if they are nested.
- .PP
- Rub_wait() will be described in detail below. Its returns
- are the new mouse position, and an indication of the current mouse
- button state. If the button remains down, the loop continues.
- When the button is released, the rubber box terminates, since it
- is a "spring-loaded" modal operation. Before ending,
- fourway_box() returns mouse control to the window manager. The
- return from the routine is found in the rubber GRECT, and is the
- final extent of the box.
- .PP
- Rub_wait() is a utility used by both box techniques. Its
- purpose is to do one step of the box animation, and wait for a
- mouse movement, or the release of the button. Rub_wait()
- preserves the state of the screen.
- .PP
- The first action is to draw an exclusive or'ed dotted line
- box at the given rectangle. Next, rub_wait() calls evnt_multi to
- wait for the mouse button to come up, or the mouse to move out of
- a one pixel rectangle. When the event is detected, the same code
- is used to remove the box. A value of TRUE is returned if the
- mouse button is still down; the curious logical construction is
- necessary since BOTH events could occur at once.
- .PP
- A short examination of the vdi_xbox() code is also useful.
- After converting the rectangle to polyline format, the vdi_xline()
- routine is called. Vdi_xline draws a dotted line, but does not
- use the VDI line style attribute. This is avoided because the VDI
- has problems with corner points when drawing styled lines in XOR
- mode. Instead, a selection is made from a set of user defined
- line styles, based on the direction of the stroke, and the
- odd/evenness of the starting horizontal pixel. This assures that
- the figure will be exactly erasable.
- .SH HOT STUFF?
- The drag box routine is more subtle, because care
- is needed to correctly synchronize the movement of the mouse
- cursor and the box, and the highlighting of target objects. The
- parameters vdi_handle and limit are identical to those in
- fourway_box(). The GRECT pointed to by box contains the width and
- height of the movable box when hot_dragbox() is entered. On exit
- it also contains the last x,y coordinates of the box. The
- variable tree is a pointer to the root of a resource tree defining
- the hot spots for the drag operation. Only objects tagged
- SELECTABLE are hotspotted. Hot_dragbox() returns the number of
- such an object if the box is "dropped" on it, otherwise a NIL is
- returned.
- .PP
- Initialization proceeds as above, until the graf_mkstate
- call. Here is the first potential synchronization problem. If
- the user moves the mouse very quickly after initiating the drag,
- it may already be outside the box by the time graf_mkstate samples
- the position. The min/max operations given lock the box onto the
- cursor, no matter where it has strayed. The mouse/box offsets, ox
- and oy, will remain constant for the rest of the operation.
- .PP
- Hover_obj will contain the number of the object which is
- currently highlighted. It is initialized to NIL, indicating no
- object is currently marked. Hot_dragbox() now enters a loop with
- termination conditions identical to the rubber box.
- .PP
- The current desired position of the box is computed by
- subtracting the box/mouse offset from the current mouse position.
- The rc_constrain() call ensures that the box will not leave the
- bounding rectangle. Note that rc_intersect would not work here -
- it would alter the size of the draggable box, rather than
- "nudging" it back into the bounds.
- .PP
- Upon return from rub_wait(), a number of conditions must be
- checked to determine the correct object to highlight, if any.
- First, we must make sure that the mouse is actually within the
- legal bounds. If not, there may be an ambiguous selection, with
- the mouse over one object and the box over another. We choose to
- do nothing in this case, and set hover_obj to NIL. If the mouse
- is in bounds, objc_find looks for a target object. If one exists,
- it must be SELECTABLE, or it is forced to NIL.
- .PP
- Next the new object, stored in ret_obj, is compared to the
- old highlighted object, in hover_obj. If they are different, a
- switch must be made. Since either could be NIL, a check is
- necessary before calling obj_toggle to invert/reinvert the screen
- image of the object. When the loop is complete, the final
- hover_obj is returned to normal state before its number is
- returned.
- .PP
- You may notice that this method of highlighting objects is
- different from the incremental tree descent and rectangles method
- presented in column 13. While not as efficient, the objc_find
- technique is simpler to code and may be adequate for many uses.
- If your program will make heavy use of the drag box routine, or
- will have large trees of target objects, you may wish to
- integrate the incremental hotspotting algorithm with
- hot_dragbox(). This would be simple to do; just use evnt_multi's
- second mouse rectangle for the states associated with the hot-
- spotter. The single pixel rectangles would have to remain, in
- order to maintain the animation effects.
- .SH A FEW CHANGES.
- The observant may have noticed that the
- promised code for popup menus did not make it into this column.
- Instead, it will appear in column 18 along with more "graphics
- potpourri" and feedback replies. The intervening installment,
- number 17, will present and document the source code for a
- complete IBM/Atari GEM Resource conversion program. This will
- appear concurrently with Mark Skapinker's article on IBM/ST GEM
- conversions in the second issue of START. While this program
- will be of direct use to only a minority of ST developers, it will
- contain utility code useful to all, as well as demonstrations of
- dialog handling and the internal structure of resources.
- .PP
- Finally, you may also notice that the so-called portability
- macros have disappeared from the download. Indeed, they are gone
- for good. Since the beginning of this column, the growth of the
- ST GEM developer community has outstripped that on the PC. It no
- longer seems appropriate to inconvenience ST developers and
- violate standard C syntax for the sake of Intel's design flaws.
- Those who still need compatibility with the PC may achieve it by
- compiling under Intel large model, or by writing "sed" scripts to
- translate (tree+obj)->ob_spec and the like to their macro
- equivalents.
- .!
- .!
- .!*****************************************************************************
- .!* *
- .!* End Part 16 *
- .!* *
- .!*****************************************************************************
-